<script>
import {DefaultForm, FormConfig} from './ConfigType';
import RenderUtils from './RenderUtils';
import typeOfUtils from "../../utils/type-of-utils";
import htmlElementUtils from "../../utils/htmlElementUtils";
import ShowTooltip from "../../directive/VshowTooltip/VshowTooltip";
import { CascadeUtils } from './CascadeUtils'

export default {
  name: 'DynamicForm',
  // 定义用到的组件
  components: {
    ...RenderUtils.getComponents(),
  },
  // 自定义指令，这里定义局部指令
  directives: {
    ShowTooltip
  },
  // 过滤器
  filters: {},
  // 定义用到的混入，可以重复使用代码
  mixins: [],
  // 属性定义使用对象的形式进行定义
  props: {
    value: {
      type: Object,
      default: () => {
      },
    },
    formConfig: {
      type: FormConfig,
      default: () => {
      },
    },
    labelAppend: {
      type: String,
      default: '',
    },
    scrollXToElement:Function, // 没有找到滚动元素时，会调用这个方法，参数：prop 返回HTMLElement
  },
  model: {
    event: 'update:value',
    prop: 'value',
  },
  render(createElement) {
    let childrens = [];
    if (this.formConfig.inline) {
      childrens = this.__formItems2ChildrensMap((item) => {
        let opacity = {}
        if (RenderUtils.setOpacity(item, this)) {
          opacity = {
            opacity: 1,
            visibility: 'hidden',
            'pointer-events': 'none',
          }
        }
        const renderFormItem = RenderUtils.renderFormItem(createElement, this, item);
        renderFormItem[0].data.style = {
          ...opacity
        }
        return renderFormItem[0]
      });
      if (this.$scopedSlots.default) {
        childrens.push(...this.$scopedSlots.default()); // 直接支持写 el-form-item 虽然支持但是都是加载后面
      }
    } else {
      const formChilds = this.__formItems2ChildrensMap((item) => {
          let opacity = {}
          if(RenderUtils.setOpacity(item,this)){
            opacity = {
              opacity: 1,
              visibility: 'hidden',
              'pointer-events': 'none',
            }
          }
          return createElement(
            'el-col',
            {
              props: {
                span: item.span || this.formConfig.span || DefaultForm.span,
              },
              style: {
                ...opacity
              },
            },
            [...RenderUtils.renderFormItem(createElement, this, item)]
          );
        });
      if (this.$scopedSlots.default) {
        formChilds.push(...this.$scopedSlots.default()); // 直接支持写 el-form-item 虽然支持但是都是加载后面
      }
      const elRow = createElement(
        'el-row',
        {
          props: {
            gutter: this.formConfig?.gutter || DefaultForm.gutter,
          },
        },
        formChilds
      );
      childrens.push(elRow);
    }
    return createElement(
      'el-form',
      {
        ref: 'elFormRef',
        props: {
          ...this.$attrs,
          ...this.formConfig,
          model: this.formData,
          disabled: false,
        },
        on: {
          ...this.$listeners,
          ...this.formConfig.events,
          validate: this.validateEvents
        },
        class: {
          localModulesZhiXinLibElementComponentsDynamicFormIndexVue:true,
          dynamic_form_not_line: !this.formConfig.inline,
          dynamic_form_line: this.formConfig.inline,
        },
      },
      childrens
    );
  },
  // 定义变量
  data() {
    return {
      formData: {},
      showFailElement:false, // 显示校验失败的位置
      /**
       * @type {HTMLElement}
       */
      parentElement:null, // 父级元素用于滚动
      watchProps: [], // 单个监听的字段和取消的方法
    };
  },
  // 定义计算属性值，加上watch配合，可以读取vuex异步获取的值
  computed: {
    // indexProps(){
    //   return this.test;
    // },
    // indexProps2: {
    //		get(){
    //			//return this.name.split('').reverse().join('');
    //			return this.firstName+''+this.lastName;
    //		},
    //		set(value){
    //		}
    // }
  },
  // 监听属性值的变化
  watch: {
    formConfig() {
      this.initFormConfig();
    },
    value:{
      handler(value) {
        this.$set(this, 'formData', value)
        Object.keys(value).forEach(key => {
          this.$set(this.formData, key, value[key])
        })
      },
      deep: true,
    },
    formData: {
      handler(value) {
        this.$emit('update:value', value);
      },
      deep: true
    },
  },
  // 生命周期钩子函数begin
  // 在页面节点挂载完执行
  // 在页面创建完执行
  created() {
    Object.keys(this.value).forEach(key=>{
      this.$set(this.formData,key,this.value[key])
    })
    this.initFormConfig();
    this.initValue();
  },
  // 生命周期钩子函数end
  // 定义方法
  methods: {
    /**
     * @param props {array | string ?}
     * @returns {*}
     */
    clearValidate(props) {
      return this.$refs.elFormRef.clearValidate(props)
    },
    /**
     * @returns {*}
     */
    resetFields() {
      return this.$refs.elFormRef.resetFields()
    },
    /**
     *
     * @param props {array | string ?}
     * @param callback {(errorMessage: string)=>void ?}
     * @returns {Promise}
     */
    validateField(props, callback) {
      if (callback) {
        this.$refs.elFormRef.validateField(props, callback)
      } else {
        return new Promise((resolve, reject) => {
          this.$refs.elFormRef.validateField(props, (e) => {
            if (e) {
              reject(e)
            } else {
              resolve()
            }
          })
        })
      }
    },
    /**
     *
     * @param parentElement {HTMLElement ?}
     * @param callBack {Function ?}
     * @returns {Promise}
     */
    validate(parentElement, callBack) {
      if (parentElement) {
        this.parentElement = parentElement
      }
      this.showFailElement = true
      if (callBack) {
        return this.$refs.elFormRef.validate(callBack)
      }
      return this.$refs.elFormRef.validate()
    },
    validateEvents(prop, bool, message) {
      if (!bool) { // 校验不通过
        if(!this.parentElement) { // 如果用户没有传入父级元素，自动尝试查找
          this.parentElement = htmlElementUtils.findScrollXParentElement(this.$refs.elFormRef.$el)
        }
        if (this.parentElement && this.showFailElement) { // 如果有父级元素
          const item = RenderUtils.propToFormItem(this.formConfig.formItems, prop)
          const ref = RenderUtils.formItemToRef(item)
          const elements = this.$refs[ref]
          if (typeOfUtils.isNotEmpty(elements)) {
            if (typeOfUtils.isArray(elements)) {
              htmlElementUtils.elementScrollX(this.parentElement, elements[0].$el)
            } else {
              htmlElementUtils.elementScrollX(this.parentElement, elements.$el)
            }
          } else { // 用户自定义位置
            if (typeOfUtils.isFunction(this.scrollXToElement)) {
              htmlElementUtils.elementScrollX(this.parentElement, this.scrollXToElement(prop))
            }
          }
          this.showFailElement = false // 只滚动一次
        }
      }
      this.$emit('validate', prop, bool, message)
    },
    resetValue() { // 可以用作重置表单的值
      RenderUtils.formItemForEach(this, (i) => {
        if (i.type === 'slot') {
          if (typeOfUtils.isFunction(i.initSlotData)) {
            i.initSlotData(this.formData, i)
          }
        } else {
          RenderUtils.initFormValue(this, i)
        }
      })
      this.$nextTick(() => {
        this.$refs.elFormRef.clearValidate();
      })
    },
    initValue() {
      RenderUtils.formItemForEach(this, (item) => {
        RenderUtils.initValueOne(this, item)
      })
    },
    __formItems2ChildrensMap(mapCallBack) {
      const result = []
      RenderUtils.formItemForEach(this,(item)=>{
        if(!RenderUtils.setHidden(item,this)){
          result.push(item)
        }
      })
      return result.map(mapCallBack)
    },
    initFormConfig() { // 添加formItems支持用函数返回
      CascadeUtils.createPropWatch(this)
      RenderUtils.formItemForEach(this, (item) => {
        RenderUtils.initFormItemConfigOne(this, item)
      })
    },
  },
};
</script>

<style scoped lang="scss">
$comHeight: 37px; // 子组件高度统一
.dynamic_form_not_line {
  ::v-deep {
    .el-select {
      width: 100%;
    }

    .el-switch{
      height: $comHeight;
      line-height: $comHeight;
    }

    .el-input-number {
      width: 100%;
    }

    .el-date-editor {
      width: 100%;
    }

    .el-input__inner {
      height: $comHeight;
      line-height: $comHeight;
    }

    .el-input-number--small {
      line-height: $comHeight;
    }

    .el-tag--small {
      height: $comHeight;
    }
  }
}
.dynamic_form_line {
  .vue-treeselect{
    width: 202px;
  }
}
</style>
<style lang="scss">
.localModulesZhiXinLibElementComponentsDynamicFormIndexVue{
  &.dynamic_form_line{
    .vue-treeselect{
      div, span{
        line-height: unset;
      }
    }
    .el-form-item{
      &.el-form-item--small{
        /* small */
        .vueTreeSelectSmall .vue-treeselect__control {
          height: 32px;
        }
        .vueTreeSelectSmall .vue-treeselect__control .vue-treeselect__value-container {
          height: 32px;
          display: block;
        }
        .vueTreeSelectSmall
        .vue-treeselect__control
        .vue-treeselect__value-container
        .vue-treeselect__placeholder {
          font-size: 13px;
        }
        .vueTreeSelectSmall
        .vue-treeselect__control
        .vue-treeselect__value-container
        .vue-treeselect__single-value {
          line-height: 32px;
          font-size: 13px;
        }
      }
      &.el-form-item--mini{
        /* mini */
        .vueTreeSelectMini .vue-treeselect__control {
          height: 26px;
        }
        .vueTreeSelectMini .vue-treeselect__control .vue-treeselect__value-container {
          height: 26px;
          display: block;
        }
        .vueTreeSelectMini
        .vue-treeselect__control
        .vue-treeselect__value-container
        .vue-treeselect__placeholder {
          font-size: 12px;
        }
        .vueTreeSelectMini
        .vue-treeselect__control
        .vue-treeselect__value-container
        .vue-treeselect__single-value {
          line-height: 26px;
          font-size: 12px;
        }
      }
    }
  }
}
.vue-treeselect__portal-target.vue-treeselect.vue-treeselect--searchable.vue-treeselect--open-below.vue-treeselect--append-to-body{
  min-width: 500px;
}
</style>
